#include "forward_service.h"
#include "vpn_native.h"
#include "java_call.h"
#include "conn_monitor.h"
#include "raw_paraser.h"
#include <jni.h>

JavaVM * g_vm = NULL;
jobject g_service = NULL;

//初始化的时候会调进来一次，在这个方法里持有jvm的引用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
    g_vm = vm;
    JNIEnv* env = NULL;
    jint result = -1;

    if(g_vm){
        LOGD("VM init success");
    }else{
        LOGD("VM init failed");
    }

    if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK){
        return result;
    }
    return JNI_VERSION_1_4;
}

void Java_com_example_sample_vpn_VpnNative_parase(JNIEnv* env, jclass cls, jobject fdesc){

    jclass clazz = (env)->GetObjectClass(fdesc);
    jfieldID fid = (env)->GetFieldID(clazz,"descriptor","I");

    if (!clazz || !fid) return;

    int fd = (env)->GetIntField(fdesc, fid);

    parase(fd);
}

void Java_com_example_sample_vpn_VpnNative_startForwarder(JNIEnv* env, jclass cls, jint port){
    forward_service* instance = forward_service::get_instance();
    instance->start_service(port);
}

/*
void JNICALL Java_com_example_sample_vpn_VpnNative_addWatch(JNIEnv* env, jobject thiz, jstring path){
    conn_monitor* instance = conn_monitor::get_instance();
    const char* sz_path = env->GetStringUTFChars(path, false);
    instance->add_watch(sz_path);
    env->ReleaseStringUTFChars(path, sz_path);
}
*/

void Java_com_example_sample_vpn_VpnNative_nativeInit(JNIEnv* env, jobject thiz){
    env->GetJavaVM(&g_vm);
    g_service = env->NewGlobalRef(thiz);
    LOGI("native init.");
}

// 调用JAVA函数
jint call_java_needForward(const char* ip){
    jint ret = 0;
    JNIEnv* env = NULL;
    g_vm->AttachCurrentThread(&env, NULL);

    jclass java_class = env->GetObjectClass(g_service);
    if (java_class == NULL){
        LOGE("failed to find class!");
    }else{
        jmethodID method_id = env->GetMethodID(java_class, "needForward", "(Ljava/lang/String;)I");
        if (method_id == NULL){
            LOGE("failed to find method!");
        }else{
            ret = env->CallIntMethod(g_service, method_id, ip);
            LOGI("call_java_needForward ret %d", ret);
        }
    }
    return ret;
}

void call_java_saveForward(const char* ip, jint forward){
    JNIEnv* env = NULL;
    g_vm->AttachCurrentThread(&env, NULL);

    jclass java_class = env->GetObjectClass(g_service);
    if (java_class == NULL){
        LOGE("failed to find class!");
        return;
    }

    jmethodID method_id = env->GetMethodID(java_class, "saveForward", "(Ljava/lang/String;I)V");
    if (method_id == NULL){
        LOGE("failed to find method!");
        return;
    }

    env->CallVoidMethod(g_service, method_id, ip, forward);
    LOGI("call_java_saveForward ret %s %d", ip, forward);

    return;
}

void call_java_protectSocket(jint fd){

	JNIEnv* env = NULL;
	g_vm->AttachCurrentThread(&env, NULL);

	jclass java_class = env->GetObjectClass(g_service);
	if (java_class == NULL){
		LOGE("failed to find class!");
		return;
	}
	jmethodID method_id = env->GetMethodID(java_class, "protectSocket", "(I)V");
	if (method_id == NULL){
		LOGE("failed to find method!");
		return;
	}
	env->CallVoidMethod(g_service, method_id, fd);
}

jint call_java_is_game_uid(jint uid){
	jint ret = 0;
	JNIEnv* env = NULL;
	g_vm->AttachCurrentThread(&env, NULL);

	jclass java_class = env->GetObjectClass(g_service);
	if (java_class == NULL){
		LOGE("failed to find class!");
	}else{
		jmethodID method_id = env->GetMethodID(java_class, "isGameUid", "(I)I");
		if (method_id == NULL){
			LOGE("failed to find method!");
		}else{
			ret = env->CallIntMethod(g_service, method_id, uid);
			LOGI("call_java_is_game_uid ret %d", ret);
		}
	}
	return ret;
}

